package com.example.jt.jtrefreshandroid;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;


/**
 * Created by william on 16/4/11.
 */
public class JTRefresh extends LinearLayout implements View.OnTouchListener {

    private static final int REFRESHHEIGHT = 200;
    private String[] titles_header = new String[]{"继续下拉可刷新页面","松手开始刷新","正在刷新请稍后"};
    private String[] titles_footer = new String[]{"继续上推可加载更多","松手开始加载","正在加载请稍后"};
    private LinearLayout ll;
    private LinearLayout header;
    private ProgressBar pb_header;
    private ImageView iv_header;
    private TextView tv_header;
    private LinearLayout footer;
    private ProgressBar pb_footer;
    private ImageView iv_footer;
    private TextView tv_footer;
    private JTRefreshListener mListener;
    private ListView mLv;
    private int currentLocation;
    private Statu statu = Statu.起始状态;


    /**
     * 目前遗留的问题，刷新中或者加载中手指再次触摸屏幕，控件就自己飞走了
     * 改变控件头脚显示状态的代码被注释掉了
     * 
     * @param context
     * @param lv
     */

    public JTRefresh(Context context, ListView lv) {
        super(context);

        //初始化容器
        ll = new LinearLayout(context);
        ll.setOrientation(VERTICAL);
        LayoutParams lp_ll = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        lp_ll.topMargin = -REFRESHHEIGHT;
        ll.setLayoutParams(lp_ll);
        this.addView(ll);

        //初始化头部
        initialHeader(context);

        //初始化内部视图，暂用listview
        if(lv == null){
            this.mLv = new ListView(context);
        }else{
            this.mLv = lv;
        }

        LayoutParams lp_mLv = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        mLv.setLayoutParams(lp_mLv);
        ll.addView(mLv);
        mLv.setBackgroundColor(Color.GREEN);
        mLv.setOnTouchListener(this);

        //初始化脚部
        initialFooter(context);
    }

    /**
     * 初始化头部控件
     * @param context
     */
    private void initialHeader(Context context){
        //初始化头部
        header = new LinearLayout(context);
        LayoutParams lp_header = new LayoutParams(LayoutParams.MATCH_PARENT,REFRESHHEIGHT);
        header.setLayoutParams(lp_header);
        header.setOrientation(HORIZONTAL);
        header.setGravity(Gravity.CENTER);
        ll.addView(header);

        //初始化头部箭头
        iv_header = new ImageView(context);
        Drawable d_header = getResources().getDrawable(R.drawable.arrow);
        iv_header.setImageDrawable(d_header);
        iv_header.setVisibility(VISIBLE);
        header.addView(iv_header);

        //初始化头部进度环
        pb_header = new ProgressBar(context);
        RelativeLayout.LayoutParams lp_pb_header = new RelativeLayout.LayoutParams(50,50);
        pb_header.setLayoutParams(lp_pb_header);
        pb_header.setVisibility(INVISIBLE);
        header.addView(pb_header);

        //初始化头部刷新提示
        tv_header = new TextView(context);
        tv_header.setText(titles_header[0]);
        header.addView(tv_header);
    }

    /**
     * 初始化脚部控件
     * @param context
     */
    private void initialFooter(Context context){
        //初始化脚部
        footer = new LinearLayout(context);
        LayoutParams lp_footer = new LayoutParams(LayoutParams.MATCH_PARENT,REFRESHHEIGHT);
        footer.setLayoutParams(lp_footer);
        footer.setOrientation(HORIZONTAL);
        footer.setGravity(Gravity.CENTER);
        ll.addView(footer);

        //初始化脚部箭头
        iv_footer = new ImageView(context);
        Matrix matrix = new Matrix();
        Bitmap bitmap = ((BitmapDrawable)(getResources().getDrawable(R.drawable.arrow))).getBitmap();
        matrix.setRotate(180);
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        iv_footer.setImageBitmap(bitmap);
        iv_footer.setVisibility(VISIBLE);
        footer.addView(iv_footer);

        //初始化脚部进度环
        pb_footer = new ProgressBar(context);
        RelativeLayout.LayoutParams lp_pb_footer = new RelativeLayout.LayoutParams(50,50);
        pb_footer.setLayoutParams(lp_pb_footer);
        pb_footer.setVisibility(INVISIBLE);
        footer.addView(pb_footer);

        //初始化脚部刷新提示
        tv_footer = new TextView(context);
        tv_footer.setText(titles_footer[0]);
        footer.addView(tv_footer);
    }


    /**
     * 控件操作的几种位置
     */
    public enum Statu {
        起始状态,移动中,下拉到一半,完全下拉,上推到一半,完全上推,刷新中,加载中,释放中;
    }


    private float yDown;
    @Override
    public boolean onTouch(View v, MotionEvent event) {

        int distance = 0;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                yDown = event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:

                distance = (int) (event.getRawY() - yDown);
                int result = isAbleToPull();
                if(result==1 && distance>0 || result==2 && distance<0) {
                    statu = Statu.移动中;
                    System.out.println("移动中........");
                    ll.setTop(-REFRESHHEIGHT + distance / 2);
                }
                //当控件移动到指定位置时，改变header和footer的图片状态方向和文字提示信息
                if(statu == Statu.移动中) {
                    if (distance / 2 >= REFRESHHEIGHT) {
                        this.statu = Statu.完全下拉;
                        changeDisplay();
                    } else if (distance / 2 <= -REFRESHHEIGHT) {
                        this.statu = Statu.完全上推;
                        changeDisplay();
                    }
                }
                break;
            default:

                currentLocation = ll.getTop();
                if(currentLocation>-REFRESHHEIGHT && currentLocation<0){
                    statu = Statu.下拉到一半;
                    new GoBackTask().execute();
                } else if (statu != Statu.刷新中 && currentLocation>=0){
                    statu = Statu.刷新中;
                    changeDisplay();
                    new GoActionTask().execute();
                } else if (currentLocation<-REFRESHHEIGHT && currentLocation > -REFRESHHEIGHT*2){
                    statu = Statu.上推到一半;
                    new GoBackTask().execute();
                } else if (statu != Statu.加载中 && currentLocation<=-REFRESHHEIGHT*2){
                    statu = Statu.加载中;
                    changeDisplay();
                    new GoActionTask().execute();
                }
        }

        // 当前正处于下拉或释放状态，要让ListView失去焦点，否则容易引起事件冲突！
        //if (statu == Statu.移动中 || statu == Statu.下拉到一半 || statu == Statu.完全下拉 || statu == Statu.上推到一半 || statu == Statu.完全上推 || statu == Statu.释放中) {
        if(statu != Statu.起始状态){
                    //updateHeaderView();

                    // 当前正处于下拉或释放状态，要让ListView失去焦点，否则被点击的那一项会一直处于选中状态
            mLv.setPressed(false);
            mLv.setFocusable(false);
            mLv.setFocusableInTouchMode(false);
            //当前正处于下拉或释放状态，通过返回true消耗掉ListView的滚动事件
            return true;
        }
        return false;
    }

    private void changeDisplay(){

        //这里都注释掉是因为，如果在下拉时改变箭头朝向和文字，会从新布局，导致屏幕闪一下，并且listView向上移位。

//        switch (statu){
//
//            case 起始状态:
//                rotateImageView(0f,180f);
//                tv_header.setText(titles_header[0]);
//                tv_footer.setText(titles_footer[0]);
//                pb_header.setVisibility(INVISIBLE);
//                pb_footer.setVisibility(INVISIBLE);
//                iv_header.setVisibility(VISIBLE);
//                iv_footer.setVisibility(VISIBLE);
//                break;
//            case 完全下拉:
//                rotateImageView(0f,180f);
//                tv_header.setText(titles_header[1]);
//                break;
//            case 完全上推:
//                rotateImageView(0f,180f);
//                tv_footer.setText(titles_footer[1]);
//                break;
//            case 刷新中:
//                pb_header.setVisibility(VISIBLE);
//                iv_header.setVisibility(View.INVISIBLE);
//                tv_header.setText(titles_header[2]);
//                break;
//            case 加载中:
//                pb_footer.setVisibility(VISIBLE);
//                iv_footer.setVisibility(View.INVISIBLE);
//                tv_footer.setText(titles_footer[2]);
//                break;
//        }
    }

    /**
     * 根据当前ListView的滚动状态来设定
     * 的值，每次都需要在onTouch中第一个执行，这样可以判断出当前应该是滚动ListView，还是应该进行下拉。
     *
     * @return 1:可以下拉；2:可以上推；除此之外毛都不可以！
     */
    private int isAbleToPull() {

        View firstChild = mLv.getChildAt(0);

        if (firstChild != null) {
            int firstVisiblePos = mLv.getFirstVisiblePosition();
            int lastVisiblePos = mLv.getLastVisiblePosition();

            if (firstVisiblePos == 0 && firstChild.getTop() == 0) {
                return 1;
            } else if (lastVisiblePos == mLv.getAdapter().getCount()-1){

                final int lastChildIndex = lastVisiblePos - firstVisiblePos;
                final int childCount = mLv.getChildCount();
                final int index = Math.min(lastChildIndex, childCount - 1);
                final View lastChild = mLv.getChildAt(index);

                if(lastChild.getBottom() == mLv.getHeight()) {
                    System.out.println("满足下啦条件，请领导随时下啦");
                    return 2;
                }
            }
            return 0;
        } else {
            // 如果ListView中没有元素，也应该允许下拉刷新
            return 1;
        }

    }

    public void finish(){
        sleep(3000);
        System.out.println("已进入finish方法！！！");
        new GoBackTask().execute();
        //statu = Status.起始状态;
        changeDisplay();
    }

    /**
     * 根据当前的状态来旋转箭头。
     */
    private void rotateImageView(float fromDegrees, float toDegrees) {
        float pivotX = iv_header.getWidth() / 2f;
        float pivotY = iv_header.getHeight() / 2f;
        RotateAnimation animation_header = new RotateAnimation(fromDegrees, toDegrees, pivotX, pivotY);
        RotateAnimation animation_footer = new RotateAnimation(fromDegrees, toDegrees, pivotX, pivotY);
        animation_header.setDuration(200);
        animation_header.setFillAfter(true);
        animation_footer.setDuration(200);
        animation_footer.setFillAfter(true);
        iv_header.startAnimation(animation_header);
        iv_footer.startAnimation(animation_footer);
    }

    /**
     * 用来阻塞当前类定义所在的线程（当前类定义在UI线程上，就可以阻塞UI的各种活动和变化）
     * @param time  阻塞时间（毫秒）
     */
    private void sleep(int time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 松手后让控件以自定义速度到达特定位置的任务。
     */
    class GoActionTask extends AsyncTask<Void, Integer, Integer> {


        @Override
        protected Integer doInBackground(Void... params) {

            int speed = currentLocation>-REFRESHHEIGHT?-8:8;
            System.out.println("时刻准备着！！！");
            System.out.println("当前currentLocation的值为："+currentLocation);
            while(true){

                currentLocation += speed;
                publishProgress(currentLocation);
                System.out.println("正在去往目标途中.......");
                if (statu == JTRefresh.Statu.下拉到一半 && currentLocation>-REFRESHHEIGHT){
                    System.out.println("进入条件1");
                    publishProgress(-REFRESHHEIGHT);
                    break;
                } else if (statu == JTRefresh.Statu.刷新中 && currentLocation<0){
                    //完全下拉
                    System.out.println("进入条件2");
                    publishProgress(0);
                    break;
                } else if (statu == JTRefresh.Statu.加载中 && currentLocation>-REFRESHHEIGHT*2){
                    //完全上推
                    System.out.println("进入条件3");
                    publishProgress(-REFRESHHEIGHT*2);
                    break;
                } else if (statu == JTRefresh.Statu.上推到一半 && currentLocation<-REFRESHHEIGHT*2){
                    System.out.println("进入条件4");
                    publishProgress(-REFRESHHEIGHT);
                    break;
                }

                sleep(10);
            }

            return currentLocation;
        }

        @Override
        protected void onProgressUpdate(Integer... points) {
            ll.setTop(points[0]);
        }
        @Override
        protected void onPostExecute(Integer topMargin) {
            if (statu == JTRefresh.Statu.加载中) {
                mListener.onLoadMore();
                System.out.println("加载结束！！！");


            }else if (statu == JTRefresh.Statu.刷新中) {
                mListener.onRefresh();
                //if (isRefreshSucceed) {
                    //sleep(3000);
                    System.out.println("刷新结束！！！");
                    //finish();
                //}
            }
        }
        /**
         * 用来阻塞当前类定义所在的线程（当前类定义在UI线程上，就可以阻塞UI的各种活动和变化）
         * @param time  阻塞时间（毫秒）
         */
        private void sleep(int time) {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 下拉或上推到一半，未达到刷新或加载的距离就松手，或已执行完刷新/加载任务，控件回退至初始位置时执行本任务。
     */
    class GoBackTask extends AsyncTask<Void, Integer, Integer> {

        @Override
        protected Integer doInBackground(Void... params) {
            System.out.println("结束时currentLocation的值为："+currentLocation);
            System.out.println("结束时statu的值为："+statu);
            int speed = currentLocation>-REFRESHHEIGHT?-8:8;

            while(true){

                currentLocation += speed;
                publishProgress(currentLocation);
                System.out.println("正在返回的路途上.....");
                if ((statu == JTRefresh.Statu.刷新中 || statu == JTRefresh.Statu.下拉到一半) && currentLocation<-REFRESHHEIGHT) {
                    //没拉满就松手了或已刷新完，让控件返回
                    publishProgress(-REFRESHHEIGHT);
                    statu = JTRefresh.Statu.起始状态;
                    break;
                } else if ((statu == JTRefresh.Statu.加载中 || statu == JTRefresh.Statu.上推到一半) && currentLocation>-REFRESHHEIGHT){
                    System.out.println("大哥我准备返回了！");
                    //没推满就松手了或已加载完，让控件返回
                    publishProgress(-REFRESHHEIGHT);
                    statu = JTRefresh.Statu.起始状态;
                    break;
                }


//                if (statu == JTRefresh.Status.刷新中 && currentLocation<-REFRESHHEIGHT) {
//                    System.out.println("进入条件2.1");
//                    //没拉满就松手了
//                    publishProgress(-REFRESHHEIGHT);
//                    statu = JTRefresh.Status.起始状态;
//                    //changeDisplay();
//                    break;
//                } else if (statu == JTRefresh.Status.刷新中 && currentLocation<-REFRESHHEIGHT){
//                    System.out.println("进入条件2.1");
//                    //没拉满就松手了
//                    publishProgress(-REFRESHHEIGHT);
//                    statu = JTRefresh.Status.起始状态;
//                    //changeDisplay();
//                    break;
//                } else


                    sleep(10);
            }

            return currentLocation;
        }
        /**
         * 用来阻塞当前类定义所在的线程（当前类定义在UI线程上，就可以阻塞UI的各种活动和变化）
         * @param time  阻塞时间（毫秒）
         */
        private void sleep(int time) {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        @Override
        protected void onProgressUpdate(Integer... points) {
            //System.out.println("执行到最后一步了！！！！！");
            ll.setTop(points[0]);
        }
    }


    /**
     * 必须调用这个方法为本控件设置监听！
     * @param listener
     */
    public void setJTRefreshListener(JTRefreshListener listener){
        mListener = listener;
    }

    /**
     * 定义一个监听接口，用来在引用类中实现刷新和加载方法。
     */
    public interface JTRefreshListener{
        public void onRefresh();
        public void onLoadMore();
    }
}
